package com.robusta.spreadsheet.model.impl;

import com.robusta.spreadsheet.model.SheetHeaders;
import com.robusta.spreadsheet.model.WorksheetTemplate;
import com.robusta.spreadsheet.model.exception.WorkbookException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.robusta.spreadsheet.model.impl.RobustaSheetHeaders.HeaderCell.newHeaderCell;
import static com.robusta.spreadsheet.model.impl.RobustaSheetHeaders.RowIndex.newRowIndex;

/**
 */
public class RobustaSheetHeaders implements SheetHeaders {
    private Map<RowIndex, HeaderCell> headersByPosition = newHashMap();
    private Map<String, HeaderCell> headersByText = newHashMap();
    private Row row;
    private WorksheetTemplate template;
    private List<com.robusta.spreadsheet.model.HeaderCell> headers = newArrayList();

    protected RobustaSheetHeaders(Row row, WorksheetTemplate template) {
        this.row = row;
        this.template = template;
        initialize();
    }

    private void initialize() {
        short lastHeaderCellInRow = row.getLastCellNum();
        for (int i = template.getStartColumnIndex(); i < lastHeaderCellInRow; i++) {
            HeaderCell headerCell = newHeaderCell(row.getCell(i), i);
            headersByPosition.put(newRowIndex(i), headerCell);
            headersByText.put(headerCell.getText(), headerCell);
            headers.add(headerCell);
        }
    }

    @Override
    public com.robusta.spreadsheet.model.HeaderCell getHeaderAt(int position) throws WorkbookException {
        RowIndex rowIndex = newRowIndex(position);
        if(headersByPosition.containsKey(rowIndex)) {
            return headersByPosition.get(rowIndex);
        }
        throw new WorkbookException(String.format("Sheet headers does not contain header cell at position: %s", position));
    }

    @Override
    public com.robusta.spreadsheet.model.HeaderCell getHeaderByText(String headerText) throws WorkbookException {
        if(headersByText.containsKey(headerText)) {
            return headersByText.get(headerText);
        }
       throw new WorkbookException(String.format("Sheet headers does not contain header cell with header text: %s", headerText));
    }

    @Override
    public Iterator<com.robusta.spreadsheet.model.HeaderCell> iterator() {
        return headers.iterator();
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("RobustaSheetHeaders");
        sb.append("{headers=").append(headers);
        sb.append('}');
        return sb.toString();
    }

    static class RowIndex {
        private int rowIndex;
        
        public static RowIndex newRowIndex(int i) {
            return new RowIndex(i);
        }

        private RowIndex(int rowIndex) {
            this.rowIndex = rowIndex;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            RowIndex rowIndex1 = (RowIndex) o;

            if (rowIndex != rowIndex1.rowIndex) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return rowIndex;
        }
    }

    static class HeaderCell implements com.robusta.spreadsheet.model.HeaderCell {
        private String headerText;
        private int position;

        public static HeaderCell newHeaderCell(Cell cell, int positionInHeaderRow) {
            checkArgument(cell != null, "Cannot initialize HeaderCell with a invalid POI cell element.");
            return new HeaderCell(cell.getStringCellValue(), positionInHeaderRow);
        }

        private HeaderCell(String headerText, int positionInHeaderRow) {
            checkArgument(!isNullOrEmpty(headerText), String.format("Cannot initialize HeaderCell with invalid content: '%s' for header row position: %s", headerText, positionInHeaderRow));
            this.headerText = headerText;
            this.position = positionInHeaderRow;
        }

        @Override
        public String getText() {
            return headerText;
        }

        public int getPosition() {
            return position;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("HeaderCell");
            sb.append("{headerText='").append(headerText).append('\'');
            sb.append(", position=").append(position);
            sb.append('}');
            return sb.toString();
        }
    }
}
